<?php

class ImageException extends Exception {}
/**
 * Description of Image
 *
 * @author Martin Grossmann <snake.aas@gmail.com>
 * @version 1.0
 * @package Images
 * 
 * @property-read $ImageInfo Information about image
 * @property-read $ExifInfo Information about image
 * @property-read $OutputFile Path, where is image saved
 */
class Image {    

  const IMAGE_QUALITY_LOW = 1;
  const IMAGE_QUALITY_MEDIUM = 2;
  const IMAGE_QUALITY_HIGH = 3;
  
  private $_inputFileName;
  private $_image = null;
  private $_exif = null;
  private $_outputFileName = null;
  
  private $_imageInfo;
  
  public function __construct($fileName) {    
    $this->_inputFileName = $fileName;
    $this->_imageInfo = new ImageInfo();

    $this->_imageInfo->ImageType = exif_imagetype($fileName);
    
    if ($this->_imageInfo->ImageType != IMAGETYPE_JPEG &&
        $this->_imageInfo->ImageType != IMAGETYPE_PNG &&
        $this->_imageInfo->ImageType != IMAGETYPE_GIF) {
      throw new ImageException(T_('Unsupported file'));  
    }
    
    $tmp = getimagesize($fileName);
    
    if ($tmp === false) throw new ImageException(T_('Unsupported file'));  
    
    $this->_imageInfo->Height   = $tmp[1];
    $this->_imageInfo->Width    = $tmp[0];
    $this->_imageInfo->Size     = filesize($fileName);

    $this->_exif = new exifInfo($fileName);
  }
  
  public function __get($name) {
    
    switch ($name) {
      
      case 'ImageInfo':
        return $this->_imageInfo;
        break;

      case 'OutputFile':
        return $this->_outputFileName;
        break;

      case 'ExifInfo':
        return $this->_exif;
        break;
    }
    
  }
  
  public function rotateImageByExif() {
    
    switch ($this->_exif->Orientation) {
      case exifInfo::ORIENTATION_NORMAL:              // do Nothing
        break;      
      
      case exifInfo::ORIENTATION_FLIP_HORIZONTAL: // flip horizontal
        break;      
      
      case exifInfo::ORIENTATION_180: // rotate 180
        $this->_image = @imagerotate($this->_image, 180, 0);
        
        if ($this->_image === false) throw new ImageException(T_('Error while rotating the picture'));
        
        $this->_exif->Orientation = exifInfo::ORIENTATION_NORMAL;
        break;      
      
      case exifInfo::ORIENTATION_FLIP_VERTICAL: // flip vertical
        break;      
      
      case exifInfo::ORIENTATION_TRANSPOSE: // flip vertical + rotate 270
        break;      
      
      case exifInfo::ORIENTATION_270: // rotate 270
        $this->_image = @imagerotate($this->_image, 270, 0);
        
        if ($this->_image === false) throw new ImageException(T_('Error while rotating the picture'));
        
        $this->_imageInfo->Width  ^= $this->_imageInfo->Height;
        $this->_imageInfo->Height ^= $this->_imageInfo->Width;
        $this->_imageInfo->Width  ^= $this->_imageInfo->Height;

        $this->_exif->Orientation = exifInfo::ORIENTATION_NORMAL;
        break;
      
      case exifInfo::ORIENTATION_TRANSVERSE: // flip horizontal + rotate 270
        break;      
      
      case exifInfo::ORIENTATION_90: // rotate 90
        $this->_image = @imagerotate($this->_image, 90, 0);
        
        if ($this->_image === false) throw new ImageException(T_('Error while rotating the picture'));
        
        $this->_imageInfo->Width  ^= $this->_imageInfo->Height;
        $this->_imageInfo->Height ^= $this->_imageInfo->Width;
        $this->_imageInfo->Width  ^= $this->_imageInfo->Height;

        $this->_exif->Orientation = exifInfo::ORIENTATION_NORMAL;
        break;            
    }
  }
  
  public function resizeImage($longestSide) {

    $doResize = true;
    
    if ($this->_imageInfo->Orientation == ImageInfo::IMAGE_LANDSCAPE) {      
      if($longestSide >= $this->_imageInfo->Width) $doResize = false;
      $newWidth = $longestSide;
      $newHeight = round(($this->_imageInfo->Height * $newWidth) / $this->_imageInfo->Width);
    } else {
      if($longestSide >= $this->_imageInfo->Height) $doResize = false;
      $newHeight = $longestSide;
      $newWidth = round(($this->_imageInfo->Width * $newHeight) / $this->_imageInfo->Height);
    }

    
    
    if($this->_image == null) {
      switch ($this->_imageInfo->ImageType) {
        case IMAGETYPE_JPEG:
          $originalImage = imagecreatefromjpeg($this->_inputFileName);
          break;

        case IMAGETYPE_PNG:
          $originalImage = imagecreatefrompng($this->_inputFileName);
          break;

        case IMAGETYPE_GIF:
          $originalImage = imagecreatefromgif($this->_inputFileName);
          break;

        default: throw new ImageProcessingException(T_('Unsupported type of image'));
      }
    } else {
      $originalImage = $this->_image;
    }
    
    if (!$doResize) {
      $this->_image = $originalImage;
      return;
    }  
    
    if ($originalImage === false) throw new ImageException(T_('Can\'t load picture for resizing'));
    
    $this->_image = @imagecreatetruecolor($newWidth, $newHeight);
    
    if ($this->_image === false) throw new ImageException(T_('Can\'t create new picture'));
    
    $bool = @imagecopyresampled($this->_image, $originalImage, 0, 0, 0, 0, $newWidth, $newHeight, $this->_imageInfo->Width, $this->_imageInfo->Height);
    if($bool === false) throw new ImageException(T_('Can\'t create new picture'));

    @imagedestroy($originalImage);
    $originalImage = null;    

    $this->_imageInfo->Width  = $newWidth;
    $this->_imageInfo->Height = $newHeight;
  }

  public function saveImage($path, $name = null, $quality = self::IMAGE_QUALITY_MEDIUM) {

    if ($name === null) {
      $name = $this->_generateName(8).image_type_to_extension($this->_imageInfo->ImageType);
    }

    if(!file_exists($path)) mkdir($path);

    switch ($this->_imageInfo->ImageType) {
      case IMAGETYPE_JPEG:

        switch ($quality) {
          case self::IMAGE_QUALITY_LOW:
            $qual = 50;
            break;
          case self::IMAGE_QUALITY_MEDIUM:
            $qual = 75;
            break;
          case self::IMAGE_QUALITY_HIGH:
            $qual = 100;
            break;
        }
        
        $bool = @imagejpeg($this->_image, $path.$name, $qual);
        break;

      case IMAGETYPE_PNG:

        switch ($quality) {
          case self::IMAGE_QUALITY_LOW:
            $qual = 4;
            break;
          case self::IMAGE_QUALITY_MEDIUM:
            $qual = 2;
            break;
          case self::IMAGE_QUALITY_HIGH:
            $qual = 0;
            break;
        }
        
        $bool = @imagepng($this->_image, $path.$name, $qual);
        break;

      case IMAGETYPE_GIF:        
        $bool = @imagegif($this->_image, $path.$name);
        break;

      default: throw new ImageException(T_('Unsupported type of image'));
    }
    
    if($bool === false) throw new ImageException(T_('Can\'t save new picture'));

    $this->_outputFileName = $path.$name;
    $this->_imageInfo->Size = @filesize($path.$name);
    
    if($this->_imageInfo->Size === false) throw new ImageException(T_('File unreachable'));
  }

  public function dispose() {
    @imagedestroy($this->_image);
    $this->_image = null;
  }

  private function _generateName($length) {
    $chars = 'abcdef1234567890';
    $return = '';
	  for ($i = 0; $i < $length; $i++) {
      $return .= $chars{mt_rand(0,15)};
		}
    return $return;
  }  
  
  
}

?>
